// src/auth/auth.service.ts
import {
  HttpException,
  HttpStatus,
  Inject,
  Injectable,
  UnauthorizedException,
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { ConfigType } from '@nestjs/config';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { UserEntity } from '../user/entities/user.entity';
import jwtConfig from '../../config/jwt.config';
import { SignInDto } from './dto/sign-in.dto';
import { SignUpDto } from './dto/sign-up.dto';
import { HashingService } from './hashing.service';
@Injectable()
export class AuthService {
  constructor(
    @InjectRepository(UserEntity)
    private readonly userRepository: Repository<UserEntity>,
    private readonly jwtService: JwtService,
    @Inject(jwtConfig.KEY)
    private readonly jwtConfiguration: ConfigType<typeof jwtConfig>,
    private readonly hashingService: HashingService,
  ) {}

  async signUp(signUpDto: SignUpDto) {
    const { userName, password } = signUpDto;

    this.checkUserName(userName);
    const hashedPassword = await this.hashingService.hash(password);
    const user = this.userRepository.create({
      ...signUpDto,
      password: hashedPassword,
    });
    return this.userRepository.save(user);
  }

  async signIn(signInDto: SignInDto) {
    const { userName, password } = signInDto;

    const user = await this.userRepository.findOne({ where: { userName } });
    if (!user) throw new UnauthorizedException('userName not found');

    const isEqual = await this.hashingService.compare(password, user.password);
    if (!isEqual) throw new UnauthorizedException('Password is incorrect');

    return await this.generateTokens(user);
  }

  async generateTokens(user: UserEntity) {
    const token = await this.signToken<Partial<any>>(user.id, {
      userName: user.userName,
      id: user.id,
    });
    return { token };
  }

  private async signToken<T>(userId: number, payload?: T) {
    return await this.jwtService.signAsync(
      {
        sub: userId,
        ...payload,
      },
      {
        secret: this.jwtConfiguration.secret,
        audience: this.jwtConfiguration.audience,
        issuer: this.jwtConfiguration.issuer,
        expiresIn: this.jwtConfiguration.accessTokenTtl,
      },
    );
  }

  async delUser(id: string | number) {
    // 如果修改admin账户则报错，不允许修改
    if (id === 1) {
      throw new HttpException(
        { message: '管理员账户不可以更改' },
        HttpStatus.BAD_REQUEST,
      );
    }
    return await this.userRepository.delete(id);
  }

  // 更新数据库某一用户的值
  async update(user: UserEntity) {
    const id = user.id;
    const hashedPassword = await this.hashingService.hash(user.password);
    // 如果修改admin账户则报错，不允许修改
    if (user.id === 1) {
      throw new HttpException(
        { message: '管理员账户不可以更改' },
        HttpStatus.BAD_REQUEST,
      );
    }
    const userTemp = await this.userRepository.findOne({
      where: { userName: user.userName },
    });
    if (userTemp && userTemp.id !== id) {
      throw new HttpException(
        { message: '该用户名已经存在！' },
        HttpStatus.BAD_REQUEST,
      );
    }
    return await this.userRepository.update(id, {
      ...user,
      password: hashedPassword,
    });
  }

  // 更新用户头像
  async updateAvatar(id: number, avatar: string) {
    return await this.userRepository.update(id, { avatar });
  }

  // 检查用户名userName是否存在
  async checkUserName(userName: string) {
    const user = await this.userRepository.findOne({ where: { userName } });
    if (user) {
      throw new HttpException(
        { message: '该用户名已经存在！' },
        HttpStatus.BAD_REQUEST,
      );
    }
  }
}
